using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Mail;
using System.Configuration;
using System.Net;
using System.Threading;

namespace FreeLancer.HRB.Core.Services
{
  /// <summary>
  /// Email utility.
  /// </summary>
  public class EmailService
  {
    /// <summary>
    /// Send e-mail.
    /// </summary>
    /// <param name="sendTo">Send to address.</param>
    /// <param name="subject">Subject of e-mail.</param>
    /// <param name="message">Message of e-mail.</param>
    /// <exception cref="System.ArgumentException"></exception>
    /// <exception cref="System.ArgumentNullException"></exception>
    /// <exception cref="System.Configuration.ConfigurationErrorsException"></exception>
    public static void SendMail(string sendTo, string subject, string message)
    {
      string sendFrom = ConfigurationManager.AppSettings[ConfigurationConstant.Email_FromAddress];
      SendMail(sendTo, sendFrom, subject, message);
    }

    /// <summary>
    /// Send e-mail.
    /// </summary>
    /// <param name="sendTo">Send to address.</param>
    /// <param name="sendFrom">Send from address.</param>
    /// <param name="subject">Subject of e-mail.</param>
    /// <param name="message">Message of e-mail.</param>
    /// <exception cref="System.ArgumentException"></exception>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="System.Configuration.ConfigurationErrorsException"></exception>
    public static void SendMail(string sendTo, string sendFrom, string subject, string message)
    {
      if (string.IsNullOrEmpty(sendTo))
      {
        throw new ArgumentException("Send address is required.");
      }
      else if (string.IsNullOrEmpty(sendFrom))
      {
        throw new ArgumentException("From address is required.");
      }
      else if ((subject == null) || (message == null))
      {
        throw new ArgumentNullException("Subject or Message must be not null.");
      }

      MailMessage messg = CreateMessage(sendTo, sendFrom, subject, message);

      try
      {
        bool enableSsl = bool.Parse(ConfigurationManager.AppSettings[ConfigurationConstant.Smtp_EnableSSL]);
        string username = ConfigurationManager.AppSettings[ConfigurationConstant.Smtp_Username];
        string password = ConfigurationManager.AppSettings[ConfigurationConstant.Smtp_Password];
        string host = ConfigurationManager.AppSettings[ConfigurationConstant.Smtp_Host];
        string port = ConfigurationManager.AppSettings[ConfigurationConstant.Smtp_Port];

        SmtpClient client = new SmtpClient();
        if (string.IsNullOrEmpty(host))
        {
          client.Host = host;
        }
        if (string.IsNullOrEmpty(port))
        {
          client.Port = int.Parse(port);
        }

        // don't send credentials if a server doesn't require it,
        // linux smtp servers don't like that 
        if (string.IsNullOrEmpty(username))
        {
          client.Credentials = new NetworkCredential(username, password);
        }
        client.EnableSsl = enableSsl;
        client.Send(messg);

        OnEmailSent(messg);
      }
      catch (Exception ex)
      {
        OnEmailFailed(messg);
        throw new System.Configuration.ConfigurationErrorsException("Invalid e-mail fields configuration.", ex);
      }
      finally
      {
        if (message != null)
        {
          messg.Dispose();
          messg = null;
        }
      }
    }

    /// <summary>
    /// Sends the mail message asynchronously in another thread.
    /// </summary>
    /// <param name="sendTo">Send to address.</param>
    /// <param name="subject">Subject of e-mail.</param>
    /// <param name="message">Message of e-mail.</param>
    /// <exception cref="System.ArgumentException"></exception>
    /// <exception cref="System.ArgumentNullException"></exception>
    /// <exception cref="System.Configuration.ConfigurationErrorsException"></exception>
    public static void SendMailAsync(string sendTo, string subject, string message)
    {
      string sendFrom = ConfigurationManager.AppSettings[ConfigurationConstant.Email_FromAddress];
      SendMailAsync(sendTo, sendFrom, subject, message);
    }

    /// <summary>
    /// Sends the mail message asynchronously in another thread.
    /// </summary>
    /// <param name="sendTo">Send to address.</param>
    /// <param name="sendFrom">Send from address.</param>
    /// <param name="subject">Subject of e-mail.</param>
    /// <param name="message">Message of e-mail.</param>
    /// <exception cref="System.ArgumentException"></exception>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="System.Configuration.ConfigurationErrorsException"></exception>
    public static void SendMailAsync(string sendTo, string sendFrom, string subject, string message)
    {
      SendMailAsync(CreateMessage(sendTo, sendFrom, subject, message));
    }

    /// <summary>
    /// Sends the mail message asynchronously in another thread.
    /// </summary>
    /// <param name="message">The message to send.</param>
    /// <exception cref="System.ArgumentException"></exception>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="System.Configuration.ConfigurationErrorsException"></exception>
    public static void SendMailAsync(MailMessage message)
    {
      ThreadPool.QueueUserWorkItem(delegate { Utils.SendMailMessage(message); });
    }

    private static MailMessage CreateMessage(string sendTo, string sendFrom, string subject, string message)
    {
      MailMessage messg = null;
      messg = new MailMessage(sendFrom, sendTo, subject, message);
      messg.IsBodyHtml = true;
      messg.BodyEncoding = Encoding.UTF8;
      return messg;
    }

    /// <summary>
    /// Occurs after an e-mail has been sent. The sender is the MailMessage object.
    /// </summary>
    public static event EventHandler<EventArgs> EmailSent;
    private static void OnEmailSent(MailMessage message)
    {
      if (EmailSent != null)
      {
        EmailSent(message, new EventArgs());
      }
    }

    /// <summary>
    /// Occurs after an e-mail has been sent. The sender is the MailMessage object.
    /// </summary>
    public static event EventHandler<EventArgs> EmailFailed;
    private static void OnEmailFailed(MailMessage message)
    {
      if (EmailFailed != null)
      {
        EmailFailed(message, new EventArgs());
      }
    }
  }
}
